package model;

import static org.junit.Assert.*;

import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Vector;

import org.junit.Test;

import analysis.ClassAnalysis2;
import analysis.MethodAnalysis;
import analysis.SysAnalysis;

public class MethodTest {


	@Test
	public void addingSetInsteadOfOneByOneParameters(){
		Vector<String> param = new Vector<String>();
		for(Integer i = 0;i<20;i++)
			param.add(new SysClass("Class"+i.toString()).getFullyQualifiedName());

		SysMethod m = new SysMethod(true,"MethodName","V", "visibility");
		m.addParameter(param);

		assertTrue(m.getParameters().equals(param.clone()));
	}

	@Test
	public void sameReturnType(){
		SysMethod m = new SysMethod(true,"MethodName","LJava.lang.String;","public");
		assertTrue(m.getReturnType().equals("LJava.lang.String;"));
	}

	@Test
	public void isADependency(){
		SysMethod m = new SysMethod(true,"MethodName","V","private");

		SysMethod d1 = new SysMethod(false,"equals","V","public");
		d1.setOwner(new SysClass("Class1"));
		SysMethod d2 = new SysMethod(false,"equals","V","public");
		d2.setOwner(new SysClass("Class2"));


		m.add(d1);
		m.add(d2);

		assertTrue(m.dependsOn(new SysClass("Class1")));
	}

	@Test
	public void isADependencyUsingSysClass(){
		SysMethod m = new SysMethod(true,"MethodName","V","private");
		SysMethod sm[] = new SysMethod[3];
		for(Integer i=0;i<3;i++){
			sm[i]=new SysMethod(false, "Method_"+i.toString(), "V", "public");
			sm[i].setOwner(new SysClass("Class"+i.toString()));
			m.add(sm[i]);
		}

		SysClass a = new SysClass("Class1");
		assertTrue(m.dependsOn(a));
	}

	@Test
	public void isntADependencyUsingClass(){
		SysMethod m = new SysMethod(true,"MethodName","V","private");
		SysMethod sm[] = new SysMethod[3];
		for(Integer i=0;i<3;i++){
			sm[i]=new SysMethod(false, "Method_"+i.toString(), "V", "public");
			sm[i].setOwner(new SysClass("Class"+i.toString()));
			m.add(sm[i]);
		}
		SysClass a = new SysClass("ClassB");
		assertFalse(m.dependsOn(a));
	}

	@Test
	public void throwsException(){
		SysMethod m = new SysMethod(true,"MethodName","ReturnType","private");
		SysException e = new SysException("MyException");
		m.addException(e.getFullyQualifiedName());
		m.addException("java/lang/Exception");
		assertTrue(m.mayThrow(e));    
	}

	@Test
	public void mayNotThrowException(){
		SysMethod m = new SysMethod(true,"MethodName","ReturnType","private");
		SysException e = new SysException("MyException");
		m.addException("java/lang/Exception");
		assertFalse(m.mayThrow(e));  
	}

	@Test
	public void sameParamList(){
		SysMethod m = new SysMethod(false,"m","v","default");
		m.addParameter("Ljava/lang/String;");
		m.addParameter("Ljava/lang/Util;");
		m.addParameter("Ljavax/swing/JFrame;");
		List<String> l = new ArrayList<String>();
		l.add("Ljava/lang/String;");
		l.add("Ljava/lang/Util;");
		l.add("Ljavax/swing/JFrame;");
		assertTrue(m.equalsParamList(l));
		
		l.remove("Ljava/lang/String;");
		assertFalse(m.equalsParamList(l));
		
		m.addParameter("[Ljava/lang/String;");
		l.add("L[java/lang/String;");
		assertFalse(m.equalsParamList(l));
		l.add("Ljava/lang/String;");
		l.add("Nothing");
		assertFalse(m.equalsParamList(l));
		l.remove("Nothing");
		m.addParameter("Nothing");
		assertFalse(m.equalsParamList(l));

	}
	
	
	@Test
	public void autoParamList(){
		String path = "."+File.separator+"test-programs"+File.separator+"Polymorphism"+File.separator;
		SysRoot autoR = SysAnalysis.initialModel(path);
		SysRoot r = new SysRoot(path);
		SysPackage p = new SysPackage("myModel");
		SysPackage p2 = new SysPackage("myMethod");
		SysClass c = new SysClass("Polymorphism");
		p2.add(c);
		p.add(p2);
		r.add(p);
		assertTrue(r.equals(autoR));
		HashSet<SysPackage> h = autoR.getPackages();
		assertTrue(h.size()==1);
		SysPackage pack = (SysPackage) h.toArray()[0];
		assertTrue(pack.contains(p2));
		SysPackage pack2 = pack.getEquals(p2);
		assertTrue(pack2!=p2);
		SysClass clazz = (SysClass) pack2.get("Polymorphism", "", false);
		assertTrue(clazz != null);
		assertTrue(clazz instanceof SysClass);
		assertTrue(clazz.equals(c));
		clazz = ClassAnalysis2.analyseClass(clazz, autoR);
		SysMethod m1_1 = new SysMethod(false,"method1","boolean", "public");
		m1_1.addParameter("boolean");
		SysMethod m1_2 = new SysMethod(false,"method1","boolean", "public");
		m1_2.addParameter("java.lang.Boolean");
		SysMethod m2 = new SysMethod(false, "method2", "java.lang.Boolean", "public");
		SysMethod main = new SysMethod(true, "main", "void", "public");
		main.addParameter("Ljava.lang.String[];");
		SysMethod init = new SysMethod(false, "<init>","void","public");
		c.add(init);
		c.add(main);
		c.add(m2);
		c.add(m1_2);
		c.add(m1_1);
		System.out.println(clazz.getMethods().toString());
		System.out.println(c.getMethods().toString());
		assertTrue(c.equals(clazz));
		for(SysMethod m : c.getMethods()){
			assertTrue(clazz.contains(m));
		}
		for(SysMethod m : clazz.getMethods()){
			assertTrue(c.contains(m));
			MethodAnalysis.analyseMethod(m, autoR);
		}
		Element en0 = clazz.get("main", "java.lang.String[]", true);
		assertTrue(en0 instanceof SysMethod);
		SysMethod auto_main = (SysMethod)en0;
		Element en1 = clazz.get("method1", "boolean", true);
		assertTrue(en1 instanceof SysMethod);
		SysMethod auto_m1_1 = (SysMethod)en1;
		Element en2 = clazz.get("method1", "java.lang.Boolean", true);
		assertTrue(en2 instanceof SysMethod);
		SysMethod auto_m1_2 = (SysMethod)en2;
		Element en3 = clazz.get("method2", "", true);
		assertTrue(en3 instanceof SysMethod);
		SysMethod auto_m2 = (SysMethod)en3;
		Element en4 = clazz.get("<init>", "", true);
		assertTrue(en4 instanceof SysMethod);
		SysMethod auto_init = (SysMethod)en4;
		
		System.out.println("[MethodTest]0: "+auto_m1_1);
		System.out.println("[MethodTest]1: "+auto_m1_2);
		System.out.println("[MethodTest]2: "+auto_m2);
		System.out.println("[MethodTest]3: "+auto_main);
		System.out.println("[MethodTest]4: "+auto_init);
		assertTrue(auto_main.dependsOn(init));
		assertTrue(auto_main.dependsOn(m1_1));
		assertTrue(auto_main.dependsOn(m2));
		assertTrue(auto_main.dependsOn(m1_2));
	}

}
